﻿using QueuesLib;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace WorkStation
{
    [ServiceContract(Name = "WorkStationNotifService")]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)] 
    public class WorkStationNotifService {
        public static readonly String OK_MSG = "OK";
        public static readonly String NOT_INITIALIZED_MSG = "Not initialized";
        public static readonly String UNEXPECTED_ARGUMENT_MSG = "Unexpected argument";
        private List<NotificationsObserver> observers = new List<NotificationsObserver>();
        private ServiceHost host;

        public bool UseLocalhost {
            get {
                return Convert.ToBoolean(ConfigurationManager.AppSettings.Get("UseLocalhost"));
            }
        }

        public bool IsListening {
            get {
                return host != null && host.State == CommunicationState.Opened;
            }
        }

        public void AddObserver(NotificationsObserver obs) {
            observers.Add(obs);
        }

        public void RemoveObserver(NotificationsObserver obs) {
            observers.Remove(obs);
        }

        public void Start() {
            try {
                var ip = UseLocalhost ? "localhost" : getIpAddress();
                var uri = new Uri("http://" + ip + ":2222/WorkStationNotifService");
                host = new ServiceHost(this, uri);
                host.Open();
                Console.WriteLine("Web service was published successfully.\n" + "WSDL URL: " + host.BaseAddresses[0] + "?WSDL");
            }
            catch (Exception e) {
                Console.Error.WriteLine(e.Message);
                Console.Error.WriteLine(e.StackTrace);
            }
        }

        public void Stop() {
            if (IsListening) {
                host.Close();
                Console.WriteLine("Service stopped.");
            }
        }

        

        [OperationContract(Name = "initialize")]
        public string Initialize(List<Subject> subjects, List<Counter> counters, List<QueueInfo> tickets) {
            try {
                foreach (var o in observers) {
                    o.Initialize(subjects, counters, tickets);
                }
                return OK_MSG;
            }
            catch (NotInitializedException) {
                return NOT_INITIALIZED_MSG;
            }
        }

        [OperationContract(Name = "update")]
        public string Update(List<Counter> counters, List<QueueInfo> tickets) {
            try {
                foreach (var o in observers) {
                    o.Update(counters, tickets);
                }
                return OK_MSG;
            }
            catch (NotInitializedException) {
                return NOT_INITIALIZED_MSG;
            }
            catch (UnknownSubjectException) {
                return UNEXPECTED_ARGUMENT_MSG;
            }
        }

        [OperationContract(Name = "ping")]
        public string Ping() {
            return "Pong :)";
        }

        private string getIpAddress() {
            foreach (var i in NetworkInterface.GetAllNetworkInterfaces()) {
                if (i.OperationalStatus == OperationalStatus.Up && i.NetworkInterfaceType != NetworkInterfaceType.Loopback){
                    foreach (var ad in i.GetIPProperties().UnicastAddresses) {
                        if (!IPAddress.IsLoopback(ad.Address) && ad.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) {
                            return ad.Address.ToString();
                        }
	                }
	            }
            }
            throw new Exception("No functional interface address was found.");
        }
    }
}
